// bdlc_flathashmap.h                                                 -*-C++-*-
#ifndef INCLUDED_BDLC_FLATHASHMAP
#define INCLUDED_BDLC_FLATHASHMAP

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide an open-addressed unordered map container.
//
//@CLASSES:
//   bdlc::FlatHashMap: open-addressed unordered map container
//
//@SEE_ALSO: bdlc_flathashtable, bdlc_flathashset
//
//@DESCRIPTION: This component defines a single class template,
// `bdlc::FlatHashMap`, that implements an open-addressed unordered map of
// items with unique keys.
//
// Unordered maps are useful in situations when there is no meaningful way to
// order key values, when the order of the keys is irrelevant to the problem
// domain, or (even if there is a meaningful ordering) the value of ordering
// the keys is outweighed by the higher performance provided by unordered maps
// (compared to ordered maps).  On platforms that support relevant SIMD
// instructions (e.g., SSE2), `bdlc::FlatHashMap` generally exhibits better
// performance than `bsl::unordered_map`.
//
// An instantiation of `bdlc::FlatHashMap` is an allocator-aware,
// value-semantic type whose salient attributes are the collection of
// `KEY-VALUE` pairs contained, without regard to order.  An instantiation may
// be provided with custom hash and key-equality functors, but those are not
// salient attributes.  In particular, when comparing element values for
// equality between two different `bdlc::FlatHashMap` objects, the elements are
// compared using `operator==`.
//
// The implemented data structure is inspired by Google's `flat_hash_map`
// CppCon presentations (available on YouTube).  The implementation draws from
// Google's open source `raw_hash_set.h` file at:
// https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal.
//
///Performance Caveats
///-------------------
// `bdlc::FlatHashMap` is recommended for Intel platforms *only* (i.e., Linux
// and Windows, and pre-ARM Macs); on platforms using other processors (i.e.,
// Sun and AIX), `bdlc::FlatHashMap` may have slower performance than
// `bsl::unordered_map`.  However, note that `bdlc::FlatHashMap` will use
// significantly less memory than `bsl::unordered_map` on *all* platforms.
// Given the Intel-only performance caveat, it is recommended to benchmark
// before using `bdlc::FlatHashMap` -- particularly on non-Intel production
// environments.
//
///Interface Differences with `unordered_map`
///------------------------------------------
// A `bdlc::FlatHashMap` meets most of the requirements of an unordered
// associative container with forward iterators in the C++11 Standard [23.2.5].
// It does not have the bucket interface, and locations of elements may change
// when the container is modified (and therefore iterators become invalid too).
// Allocator use follows BDE style, and the various allocator propagation
// attributes are not present (e.g., the allocator trait
// `propagate_on_container_copy_assignment`).  The maximum load factor of the
// container (the ratio of size to capacity) is maintained by the container
// itself and is not settable (the maximum load factor is implementation
// defined and fixed).
//
///Load Factor and Resizing
///------------------------
// An invariant of `bdlc::FlatHashMap` is that
// `0 <= load_factor() <= max_load_factor() <= 1.0`.  Any operation that would
// result in `load_factor() > max_load_factor()` for a `bdlc::FlatHashMap`
// causes the capacity to increase.  This resizing allocates new memory, copies
// or moves all elements to the new memory, and reclaims the original memory.
// The transfer of elements involves rehashing each element to determine its
// new location.  As such, all iterators, pointers, and references to elements
// of the `bdlc::FlatHashMap` are invalidated on a resize.
//
///Requirements on `KEY`, `HASH`, and `EQUAL`
///------------------------------------------
// The template parameter type `KEY` must be copy or move constructible.  The
// template parameter types `HASH` and `EQUAL` must be default and copy
// constructible function objects.
//
// `HASH` must support a function-call operator compatible with the following
// statements for an object `key` of type `KEY`:
// ```
// HASH        hash;
// bsl::size_t result = hash(key);
// ```
//
// `EQUAL` must support a function-call operator compatible with the
//  following statements for objects `key1` and `key2` of type `KEY`:
// ```
// EQUAL equal;
// bool  result = equal(key1, key2);
// ```
// where the definition of the called function defines an equivalence
// relationship on keys that is both reflexive and transitive.
//
// `HASH` and `EQUAL` function objects are further constrained: if the
// comparator determines that two values are equal, the hasher must produce the
// same hash value for each.
//
///Iterator, Pointer, and Reference Invalidation
///---------------------------------------------
// Any change in capacity of a `bdlc::FlatHashMap` invalidates all pointers,
// references, and iterators.  A `bdlc::FlatHashMap` manipulator that erases an
// element invalidates all pointers, references, and iterators to the erased
// element.
//
///Exception Safety
///----------------
// A `bdlc::FlatHashMap` is exception neutral, and all of the methods of
// `bdlc::FlatHashMap` provide the basic exception safety guarantee (see
// {`bsldoc_glossary`|Basic Guarantee}).
//
///Move Semantics in C++03
///-----------------------
// Move-only types are supported by `bdlc::FlatHashMap` on C++11, and later,
// platforms only (where `BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES` is defined),
// and are not supported on C++03 platforms.  Unfortunately, in C++03, there
// are user-defined types where a `bslmf::MovableRef` will not safely degrade
// to an lvalue reference when a move constructor is not available (types
// providing a constructor template taking any type), so
// `bslmf::MovableRefUtil::move` cannot be used directly on a user-supplied
// template parameter type.
//
///Usage
///-----
// In this section we show intended use of this component.
//
///Example 1: Gathering Document Statistics
/// - - - - - - - - - - - - - - - - - - - -
// Suppose one wished to gather statistics on the words appearing in a large
// set of documents on disk or in a database.  Gathering those statistics is
// intrusive (as one is competing for access to the documents with the regular
// users) and must be done as quickly as possible.  Moreover, the set of unique
// words appearing in those documents may be high.  The English language has in
// excess of a million words (albeit many appear infrequently), and, if the
// documents contain serial numbers, or Social Security numbers, or chemical
// formulas, etc., then the `O[log(n)]` insertion time of ordered maps may well
// be inadequate.  An unordered map, having an `O[1]` typical insertion cost,
// is a viable alternative.
//
// This example illustrates the use of `bdlc::FlatHashMap` to gather one simple
// statistic (counts of unique words) on a portion of a single document.  To
// avoid irrelevant details of acquiring the data, the data is stored in static
// arrays:
// ```
// static char document[] =
// " IN CONGRESS, July 4, 1776.\n"
// "\n"
// " The unanimous Declaration of the thirteen united States of America,\n"
// "\n"
// " When in the Course of human events, it becomes necessary for one\n"
// " people to dissolve the political bands which have connected them with\n"
// " another, and to assume among the powers of the earth, the separate\n"
// " and equal station to which the Laws of Nature and of Nature's G-d\n"
// " entitle them, a decent respect to the opinions of mankind requires\n"
// " that they should declare the causes which impel them to the\n"
// " separation.  We hold these truths to be self-evident, that all men\n"
// " are created equal, that they are endowed by their Creator with\n"
// " certain unalienable Rights, that among these are Life, Liberty and\n"
// " the pursuit of Happiness.  That to secure these rights, Governments\n"
// " are instituted among Men, deriving their just powers from the consent\n"
// " of the governed, That whenever any Form of Government becomes\n";
// ```
// First, we define an alias to make our code more comprehensible:
// ```
// typedef bdlc::FlatHashMap<bsl::string, int> WordTally;
// ```
// Next, we create an (empty) flat hash map to hold our word tallies:
// ```
// WordTally wordTally;
// ```
// Then, we define the set of characters that define word boundaries:
// ```
// const char *delimiters = " \n\t,:;.()[]?!/";
// ```
// Next, we extract the words from our document.  Note that `strtok` modifies
// the document array (which was not made `const`).
//
// For each iteration of the loop, a map entry matching the key value parsed by
// `strtok` is obtained.  On the first occurrence of a word, the map has no
// such entry, so one is created with a default value of the mapped value (0,
// just what we want in this case) and inserted into the map where it is found
// on any subsequent occurrences of the word.  The `operator[]` method returns
// a reference providing modifiable access to the mapped value.  Here, we apply
// the `++` operator to that reference to maintain a tally for the word:
// ```
// for (char *cur = strtok(document, delimiters);
//            cur;
//            cur = strtok(NULL,     delimiters)) {
//     ++wordTally[bsl::string(cur)];
// }
// ```
// Now that the data has been (quickly) gathered, we can indulge in analysis
// that is more time consuming.  For example, we can define a comparison
// function, copy the data to another container (e.g., `bsl::vector`), sort the
// entries, and determine the 10 most commonly used words in the given
// documents:
// ```
// /// Assignable equivalent to 'WordTally::value_type'.  Note that
// /// 'bsl::vector' requires assignable types.
// typedef bsl::pair<bsl::string, int> WordTallyEntry;
//
// struct WordTallyEntryCompare {
//     static bool lessThan(const WordTallyEntry& a,
//                          const WordTallyEntry& b) {
//         return a.second < b.second;
//     }
//     static bool greaterThan(const WordTallyEntry& a,
//                             const WordTallyEntry& b) {
//         return a.second > b.second;
//     }
// };
//
// bsl::vector<WordTallyEntry> array(wordTally.cbegin(), wordTally.cend());
//
// assert(10 <= array.size());
//
// bsl::partial_sort(array.begin(),
//                   array.begin() + 10,
//                   array.end(),
//                   WordTallyEntryCompare::greaterThan);
// ```
// Notice that `partial_sort` suffices here since we seek only the 10 most used
// words, not a complete distribution of word counts.
//
// Finally, we print the sorted portion of `array`:
// ```
// for (bsl::vector<WordTallyEntry>::const_iterator cur  = array.begin(),
//                                                  end  = cur + 10;
//                                                  end != cur; ++cur) {
//     printf("%-10s %4d\n", cur->first.c_str(), cur->second);
// }
// ```
// and standard output shows:
// ```
// the          13
// of           10
// to            7
// that          4
// are           4
// and           4
// which         3
// these         3
// them          3
// among         3
// ```

#include <bdlscm_version.h>

#include <bdlc_flathashtable.h>

#include <bslalg_hasstliterators.h>
#include <bslalg_swaputil.h>

#include <bslh_fibonaccibadhashwrapper.h>

#include <bslim_printer.h>

#include <bslma_allocator.h>
#include <bslma_constructionutil.h>
#include <bslma_destructorguard.h>
#include <bslma_usesbslmaallocator.h>

#include <bslmf_addconst.h>
#include <bslmf_enableif.h>
#include <bslmf_isconvertible.h>
#include <bslmf_movableref.h>
#include <bslmf_util.h>    // 'forward(V)'

#include <bsls_assert.h>
#include <bsls_compilerfeatures.h>
#include <bsls_objectbuffer.h>
#include <bsls_platform.h>
#include <bsls_util.h>     // 'forward<T>(V)'

#include <bslstl_equalto.h>
#include <bslstl_hash.h>
#include <bslstl_stdexceptutil.h>

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
#include <bsl_initializer_list.h>
#endif
#include <bsl_cstddef.h>
#include <bsl_ostream.h>
#include <bsl_utility.h>

#if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
// clang-format off
// Include version that can be compiled with C++03
// Generated on Mon Jan 13 08:32:17 2025
// Command line: sim_cpp11_features.pl bdlc_flathashmap.h

# define COMPILING_BDLC_FLATHASHMAP_H
# include <bdlc_flathashmap_cpp03.h>
# undef COMPILING_BDLC_FLATHASHMAP_H

// clang-format on
#else

#if defined(BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER)
#include <bsl_type_traits.h>

    #ifndef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
    #error Rvalue references curiously absent despite native 'type_traits'.
    #endif

#endif

namespace BloombergLP {
namespace bdlc {

// FORWARD DECLARATIONS
template <class KEY,
          class VALUE,
          class HASH  = bslh::FibonacciBadHashWrapper<bsl::hash<KEY> >,
          class EQUAL = bsl::equal_to<KEY> >
class FlatHashMap;

template <class KEY, class VALUE, class HASH, class EQUAL>
bool operator==(const FlatHashMap<KEY, VALUE, HASH, EQUAL> &lhs,
                const FlatHashMap<KEY, VALUE, HASH, EQUAL> &rhs);

template <class KEY, class VALUE, class HASH, class EQUAL>
bool operator!=(const FlatHashMap<KEY, VALUE, HASH, EQUAL> &lhs,
                const FlatHashMap<KEY, VALUE, HASH, EQUAL> &rhs);

template <class KEY, class VALUE, class HASH, class EQUAL>
void swap(FlatHashMap<KEY, VALUE, HASH, EQUAL>& a,
          FlatHashMap<KEY, VALUE, HASH, EQUAL>& b);

                       // ============================
                       // struct FlatHashMap_EntryUtil
                       // ============================

/// This templated utility provides methods to construct an `ENTRY` and a
/// method to extract the key from an `ENTRY`.
template <class KEY, class VALUE, class ENTRY>
struct FlatHashMap_EntryUtil
{
    // CLASS METHODS
#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
    /// Load into the specified `entry` the `ENTRY` value constructed from
    /// specified `args`, using the specified `allocator` to supply memory.
    ///  `allocator` is ignored if the (template parameter) type `ENTRY` is
    /// not allocator aware.
    template <class... ARGS>
    static void construct(
                        ENTRY                                       *entry,
                        bslma::Allocator                            *allocator,
                        ARGS&&...                                    args);
#endif

    /// Load into the specified `entry` the `ENTRY` value comprised of the
    /// specified `key` and a default constructed `VALUE`, using the
    /// specified `allocator` to supply memory.  `allocator` is ignored if
    /// the (template parameter) type `ENTRY` is not allocator aware.
    template <class KEY_TYPE>
    static void constructFromKey(
                        ENTRY                                       *entry,
                        bslma::Allocator                            *allocator,
                        BSLS_COMPILERFEATURES_FORWARD_REF(KEY_TYPE)  key);

    /// Return the key of the specified `entry`.
    static const KEY& key(const ENTRY& entry);
};

                            // =================
                            // class FlatHashMap
                            // =================

/// This class template implements a value-semantic container type holding
/// an unordered map of `KEY-VALUE` pairs having unique keys that provides a
/// mapping from keys of (template parameter) type `KEY` to their associated
/// mapped values of (template parameter) type `VALUE`.  The (template
/// parameter) type `HASH` is a functor providing the hash value for `KEY`.
/// The (template parameter) type `EQUAL` is a functor providing the
/// equality function for two `KEY` values.  See {Requirements on `KEY`,
/// `HASH`, and `EQUAL`} for more information.
template <class KEY, class VALUE, class HASH, class EQUAL>
class FlatHashMap {

  private:
    // PRIVATE TYPES

    /// This is the underlying implementation class.
    typedef FlatHashTable<KEY,
                          bsl::pair<KEY, VALUE>,
                          FlatHashMap_EntryUtil<KEY,
                                                VALUE,
                                                bsl::pair<KEY, VALUE> >,
                          HASH,
                          EQUAL> ImplType;

    // FRIENDS
    friend bool operator==<>(const FlatHashMap&, const FlatHashMap&);
    friend bool operator!=<>(const FlatHashMap&, const FlatHashMap&);

    // The following verbose declaration is required by the xlC 12.1 compiler.
    template <class K, class V, class H, class E>
    friend void swap(FlatHashMap<K, V, H, E>&, FlatHashMap<K, V, H, E>&);

  public:
    // PUBLIC TYPES
    typedef bsl::pair<typename bsl::add_const<KEY>::type, VALUE> value_type;

    typedef KEY                                key_type;
    typedef VALUE                              mapped_type;
    typedef bsl::size_t                        size_type;
    typedef bsl::ptrdiff_t                     difference_type;
    typedef EQUAL                              key_compare;
    typedef HASH                               hasher;
    typedef value_type&                        reference;
    typedef const value_type&                  const_reference;
    typedef value_type*                        pointer;
    typedef const value_type*                  const_pointer;
    typedef typename ImplType::iterator        iterator;
    typedef typename ImplType::const_iterator  const_iterator;

  private:
    // DATA
    ImplType d_impl;  // underlying flat hash table used by this flat hash map

  public:
    // CREATORS

    /// Create an empty `FlatHashMap` object.  Optionally specify a
    /// `capacity` indicating the minimum initial size of the underlying
    /// array of entries of this container.  If `capacity` is not supplied
    /// or is 0, no memory is allocated.  Optionally specify a `hash`
    /// functor used to generate the hash values associated with the keys of
    /// elements in this container.  If `hash` is not supplied, a
    /// default-constructed object of the (template parameter) type `HASH`
    /// is used.  Optionally specify an equality functor `equal` used to
    /// determine whether the keys of two elements are equivalent.  If
    /// `equal` is not supplied, a default-constructed object of the
    /// (template parameter) type `EQUAL` is used.  Optionally specify a
    /// `basicAllocator` used to supply memory.  If `basicAllocator` is not
    /// supplied or is 0, the currently installed default allocator is used.
    FlatHashMap();
    explicit FlatHashMap(bslma::Allocator *basicAllocator);
    explicit FlatHashMap(bsl::size_t capacity);
    FlatHashMap(bsl::size_t capacity, bslma::Allocator *basicAllocator);
    FlatHashMap(bsl::size_t       capacity,
                const HASH&       hash,
                bslma::Allocator *basicAllocator = 0);
    FlatHashMap(bsl::size_t       capacity,
                const HASH&       hash,
                const EQUAL&      equal,
                bslma::Allocator *basicAllocator = 0);

    /// Create a `FlatHashMap` object initialized by insertion of the values
    /// from the input iterator range specified by `first` through `last`
    /// (including `first`, excluding `last`).  Optionally specify a
    /// `capacity` indicating the minimum initial size of the underlying
    /// array of entries of this container.  If `capacity` is not supplied
    /// or is 0, no memory is allocated.  Optionally specify a `hash`
    /// functor used to generate hash values associated with the keys of the
    /// elements in this container.  If `hash` is not supplied, a
    /// default-constructed object of the (template parameter) type `HASH`
    /// is used.  Optionally specify an equality functor `equal` used to
    /// determine whether the keys of two elements are equivalent.  If
    /// `equal` is not supplied, a default-constructed object of the
    /// (template parameter) type `EQUAL` is used.  Optionally specify a
    /// `basicAllocator` used to supply memory.  If `basicAllocator` is not
    /// supplied or is 0, the currently installed default allocator is used.
    /// The behavior is undefined unless `first` and `last` refer to a
    /// sequence of valid values where `first` is at a position at or before
    /// `last`.  Note that if a member of the input sequence has an
    /// equivalent key to an earlier member, the later member will not be
    /// inserted.
    template <class INPUT_ITERATOR>
    FlatHashMap(INPUT_ITERATOR    first,
                INPUT_ITERATOR    last,
                bslma::Allocator *basicAllocator = 0);
    template <class INPUT_ITERATOR>
    FlatHashMap(INPUT_ITERATOR    first,
                INPUT_ITERATOR    last,
                bsl::size_t       capacity,
                bslma::Allocator *basicAllocator = 0);
    template <class INPUT_ITERATOR>
    FlatHashMap(INPUT_ITERATOR    first,
                INPUT_ITERATOR    last,
                bsl::size_t       capacity,
                const HASH&       hash,
                bslma::Allocator *basicAllocator = 0);
    template <class INPUT_ITERATOR>
    FlatHashMap(INPUT_ITERATOR    first,
                INPUT_ITERATOR    last,
                bsl::size_t       capacity,
                const HASH&       hash,
                const EQUAL&      equal,
                bslma::Allocator *basicAllocator = 0);

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
    /// Create a `FlatHashMap` object initialized by insertion of the
    /// specified `values`.  Optionally specify a `capacity` indicating the
    /// minimum initial size of the underlying array of entries of this
    /// container.  If `capacity` is not supplied or is 0, no memory is
    /// allocated.  Optionally specify a `hash` functor used to generate
    /// hash values associated with the keys of elements in this container.
    /// If `hash` is not supplied, a default-constructed object of the
    /// (template parameter) type `HASH` is used.  Optionally specify an
    /// equality functor `equal` used to determine whether the keys of two
    /// elements are equivalent.  If `equal` is not supplied, a
    /// default-constructed object of the (template parameter) type `EQUAL`
    /// is used.  Optionally specify a `basicAllocator` used to supply
    /// memory.  If `basicAllocator` is not supplied or is 0, the currently
    /// installed default allocator is used.  Note that if a member of
    /// `values` has an equivalent key to an earlier member, the later
    /// member will not be inserted.
    FlatHashMap(bsl::initializer_list<value_type>  values,
                bslma::Allocator                  *basicAllocator = 0);
    FlatHashMap(bsl::initializer_list<value_type>  values,
                bsl::size_t                        capacity,
                bslma::Allocator                  *basicAllocator = 0);
    FlatHashMap(bsl::initializer_list<value_type>  values,
                bsl::size_t                        capacity,
                const HASH&                        hash,
                bslma::Allocator                  *basicAllocator = 0);
    FlatHashMap(bsl::initializer_list<value_type>  values,
                bsl::size_t                        capacity,
                const HASH&                        hash,
                const EQUAL&                       equal,
                bslma::Allocator                  *basicAllocator = 0);
#endif

    /// Create a `FlatHashMap` object having the same value, hasher, and
    /// equality comparator as the specified `original` object.  Optionally
    /// specify a `basicAllocator` used to supply memory.  If
    /// `basicAllocator` is not specified or is 0, the currently installed
    /// default allocator is used.
    FlatHashMap(const FlatHashMap&  original,
                bslma::Allocator   *basicAllocator = 0);

    /// Create a `FlatHashMap` object having the same value, hasher,
    /// equality comparator, and allocator as the specified `original`
    /// object.  The contents of `original` are moved (in constant time) to
    /// this object, `original` is left in a (valid) unspecified state, and
    /// no exceptions will be thrown.
    FlatHashMap(bslmf::MovableRef<FlatHashMap> original);

    /// Create a `FlatHashMap` object having the same value, hasher, and
    /// equality comparator as the specified `original` object, using the
    /// specified `basicAllocator` to supply memory.  If `basicAllocator` is
    /// 0, the currently installed default allocator is used.  The allocator
    /// of `original` remains unchanged.  If `original` and the newly
    /// created object have the same allocator then the contents of
    /// `original` are moved (in constant time) to this object, `original`
    /// is left in a (valid) unspecified state, and no exceptions will be
    /// thrown; otherwise, `original` is unchanged (and an exception may be
    /// thrown).
    FlatHashMap(bslmf::MovableRef<FlatHashMap>  original,
                bslma::Allocator               *basicAllocator);

    /// Destroy this object and each of its elements.
    ~FlatHashMap();

    // MANIPULATORS

    /// Assign to this object the value, hasher, and equality functor of the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.
    FlatHashMap& operator=(const FlatHashMap& rhs);

    /// Assign to this object the value, hasher, and equality comparator of
    /// the specified `rhs` object, and return a reference providing
    /// modifiable access to this object.  If this object and `rhs` use the
    /// same allocator the contents of `rhs` are moved (in constant time) to
    /// this object.  `rhs` is left in a (valid) unspecified state.
    FlatHashMap& operator=(bslmf::MovableRef<FlatHashMap> rhs);

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
    /// Assign to this object the value resulting from first clearing this
    /// map and then inserting each object in the specified `values`
    /// initializer list, ignoring those objects having a value whose key is
    /// equivalent to that which appears earlier in the list; return a
    /// reference providing modifiable access to this object.  This method
    /// requires that the (template parameter) type `KEY` be
    /// `copy-insertable` into this map (see {Requirements on `KEY`, `HASH`,
    /// and `EQUAL`}).
    FlatHashMap& operator=(bsl::initializer_list<value_type> values);
#endif

    /// Return a reference providing modifiable access to the mapped value
    /// associated with the specified `key` in this map.  If this map does
    /// not already contain an element having `key`, insert an element with
    /// the `key` and a default-constructed `VALUE`, and return a reference
    /// to the newly mapped value.  If `key` is movable, `key` is left in a
    /// (valid) unspecified state.
    VALUE& operator[](const KEY& key);

    /// Return a reference providing modifiable access to the mapped value
    /// associated with the specified `key` in this map.  If this map does
    /// not already contain an element having `key`, insert an element with
    /// the `key` and a default-constructed `VALUE`, and return a reference
    /// to the newly mapped value.  If `key` is movable, `key` is left in a
    /// (valid) unspecified state.
    VALUE& operator[](bslmf::MovableRef<KEY> key);

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_PAIR_PIECEWISE_CONSTRUCTOR
    /// Return a reference providing modifiable access to the mapped value
    /// associated with the a key equivalent to the specified `key` in this
    /// map.  If this map does not already contain an element eqivalent to
    /// `key`, insert an element with the KEY constructed from
    /// `std::forward<LOOKUP_KEY>(k)` and a default-constructed `VALUE`, and
    /// return a reference to the newly mapped value.
    template <class LOOKUP_KEY>
    typename bsl::enable_if<
            BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
         && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
          , VALUE&>::type
    operator[](LOOKUP_KEY&& key)
    {
        return try_emplace(
                 BSLS_COMPILERFEATURES_FORWARD(LOOKUP_KEY, key)).first->second;
    }
#endif   // BSLS_LIBRARYFEATURES_HAS_CPP11_PAIR_PIECEWISE_CONSTRUCTOR
#endif

    /// Return a reference providing modifiable access to the mapped value
    /// associated with the specified `key` in this map, if such an entry
    /// exists; otherwise throw a `std::out_of_range` exception.  Note that
    /// this method is not exception-neutral.
    VALUE& at(const KEY& key);

    /// Return a reference providing modifiable access to the mapped value
    /// associated with a key that is equivalent to the specified `key` in this
    /// map, if such an entry exists; otherwise throw a `std::out_of_range`
    /// exception.  Note that this method is not exception-neutral.
    ///
    /// Note: implemented inline due to Sun CC compilation error.
    template <class LOOKUP_KEY>
    typename bsl::enable_if<
            BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
         && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
          , VALUE&>::type
    at(const LOOKUP_KEY& key)
    {
        iterator iter = find(key);
        if (iter == end()) {
            BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                             "FlatHashMap::at(LOOKUP_KEY): invalid key_value");
        }
        return iter->second;
    }

    /// Remove all elements from this map.  Note that this map will be empty
    /// after calling this method, but allocated memory may be retained for
    /// future use.  See the `capacity` method.
    void clear();

    /// Return a pair of iterators defining the sequence of modifiable
    /// elements in this map having the specified `key`, where the first
    /// iterator is positioned at the start of the sequence and the second
    /// iterator is positioned one past the end of the sequence.  If this
    /// map contains no elements having a key equivalent to `key`, then the
    /// two returned iterators will have the same value.  Note that since a
    /// map maintains unique keys, the range will contain at most one
    /// element.
    bsl::pair<iterator, iterator> equal_range(const KEY& key);

    /// Return a pair of iterators defining the sequence of modifiable
    /// elements in this map having a key equivalent to the specified `key`,
    /// where the first iterator is positioned at the start of the sequence and
    /// the second iterator is positioned one past the end of the sequence.  If
    /// this map contains no elements having a key equivalent to `key`, then
    /// the two returned iterators will have the same value.  Note that since a
    /// map maintains unique keys, the range will contain at most one
    /// element.
    ///
    /// Note: implemented inline due to Sun CC compilation error.
    template <class LOOKUP_KEY>
    typename bsl::enable_if<
            BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
         && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
          , bsl::pair<iterator, iterator> >::type
    equal_range(const LOOKUP_KEY& key)
    {
        return d_impl.equal_range(key);
    }

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
    /// Insert into this map a newly-created `value_type` object,
    /// constructed by forwarding `get_allocator()` (if required) and the
    /// specified (variable number of) `args` to the corresponding
    /// constructor of `value_type`, if a key equivalent to such a value
    /// does not already exist in this map; otherwise, this method has no
    /// effect (other than possibly creating a temporary `value_type`
    /// object).  Return a pair whose `first` member is an iterator
    /// referring to the (possibly newly created and inserted) object in
    /// this map whose key is equivalent to that of an object constructed
    /// from `args`, and whose `second` member is `true` if a new value was
    /// inserted, and `false` if an equivalent key was already present.
    /// This method requires that the (template parameter) types `KEY` and
    /// `VALUE` both be `emplace-constructible` from `args` (see
    /// {Requirements on `value_type`}).
    template <class... ARGS>
    bsl::pair<iterator, bool> emplace(ARGS&&... args);

    /// Insert into this map a newly-created `value_type` object,
    /// constructed by forwarding `get_allocator()` (if required) and the
    /// specified (variable number of) `args` to the corresponding
    /// constructor of `value_type`, if a key equivalent to such a value
    /// does not already exist in this map; otherwise, this method has no
    /// effect (other than possibly creating a temporary `value_type`
    /// object).  Return an iterator referring to the (possibly newly
    /// created and inserted) object in this map whose key is equivalent to
    /// that of an object constructed from `args`.  The average and worst
    /// case complexity of this operation is not affected by the specified
    /// `hint`.  This method requires that the (template parameter) types
    /// `KEY` and `VALUE` both be `emplace-constructible` from `args` (see
    /// {Requirements on `value_type`}).  The behavior is undefined unless
    /// `hint` is an iterator in the range `[begin() .. end()]` (both
    /// endpoints included).  Note that `hint` is ignored (other than
    /// possibly asserting its validity in some build modes).
    template <class... ARGS>
    iterator emplace_hint(const_iterator hint, ARGS&&... args);
#endif

    /// Remove from this map the element whose key is equal to the specified
    /// `key`, if it exists, and return 1; otherwise (there is no element
    /// having `key` in this map), return 0 with no other effect.  This
    /// method invalidates all iterators and references to the removed
    /// element.
    bsl::size_t erase(const KEY& key);

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
    /// Remove from this map the element whose key is equivalent to the
    /// specified `key`, if it exists, and return 1; otherwise (there is no
    /// element equivalent to `key` in this map), return 0 with no other effect.
    /// This method invalidates all iterators and references to the removed
    /// element.
    template <class LOOKUP_KEY>
    typename bsl::enable_if<
            BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
         && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
          , bsl::size_t>::type
    erase(LOOKUP_KEY&& key)
    {
        return d_impl.erase(key);
    }
#endif

    /// Remove from this map the element at the specified `position`, and
    /// return an iterator referring to the modifiable element immediately
    /// following the removed element, or to the past-the-end position if
    /// the removed element was the last element in the sequence of elements
    /// maintained by this map.  This method invalidates all iterators and
    /// references to the removed element.  The behavior is undefined unless
    /// `position` refers to an element in this map.
    iterator erase(const_iterator position);
    iterator erase(iterator position);

    /// Remove from this map the elements starting at the specified `first`
    /// position up to, but not including, the specified `last` position,
    /// and return an iterator referencing the same element as `last`.  This
    /// method invalidates all iterators and references to the removed
    /// elements.  The behavior is undefined unless `first` and `last` are
    /// valid iterators on this map, and the `first` position is at or
    /// before the `last` position in the iteration sequence provided by
    /// this container.
    iterator erase(const_iterator first, const_iterator last);

    /// Return an iterator referring to the modifiable element in this map
    /// having the specified `key`, or `end()` if no such entry exists in
    /// this map.
    iterator find(const KEY& key);

    /// Return an `iterator` referring to the modifiable element in this map
    /// having the key equivalent to the specified `key`, or `end()` if no such
    /// entry exists in this map.
    ///
    /// Note: implemented inline due to Sun CC compilation error.
    template <class LOOKUP_KEY>
    typename bsl::enable_if<
            BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
         && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
          , iterator>::type
    find(const LOOKUP_KEY& key)
    {
        return iterator(d_impl.find(key));
    }

#if defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION < 0x5130
    template <class VALUE_TYPE>
    bsl::pair<iterator, bool>
#elif !defined(BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER)
    template <class VALUE_TYPE>
    typename bsl::enable_if<bsl::is_convertible<VALUE_TYPE, value_type>::value,
                            bsl::pair<iterator, bool> >::type
#else
    /// Insert the specified `value` into this map if the key of `value`
    /// does not already exist in this map; otherwise, this method has no
    /// effect.  Return a `pair` whose `first` member is an iterator
    /// referring to the (possibly newly inserted) modifiable element in
    /// this map whose key is equivalent to that of the element to be
    /// inserted, and whose `second` member is `true` if a new element was
    /// inserted, and `false` if an element with an equivalent key was
    /// already present.
    template <class VALUE_TYPE>
    typename bsl::enable_if<bsl::is_constructible<value_type,
                                                  VALUE_TYPE&&>::value,
                            bsl::pair<iterator, bool> >::type
#endif
    insert(BSLS_COMPILERFEATURES_FORWARD_REF(VALUE_TYPE) value)
    {
        // Note that some compilers require functions declared with 'enable_if'
        // to be defined inline.

        return d_impl.insert(BSLS_COMPILERFEATURES_FORWARD(VALUE_TYPE, value));
    }

#if defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION < 0x5130
    template <class VALUE_TYPE>
    iterator
#elif !defined(BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER)
    template <class VALUE_TYPE>
    typename bsl::enable_if<bsl::is_convertible<VALUE_TYPE, value_type>::value,
                            iterator>::type
#else
    /// Insert the specified `value` into this map if the key of `value`
    /// does not already exist in this map; otherwise, this method has no
    /// effect.  Return an iterator referring to the (possibly newly
    /// inserted) modifiable element in this map whose key is equivalent to
    /// that of the element to be inserted.  The supplied `const_iterator`
    /// is ignored.
    template <class VALUE_TYPE>
    typename bsl::enable_if<bsl::is_constructible<value_type,
                                                  VALUE_TYPE&&>::value,
                            iterator>::type
#endif
    insert(const_iterator                                ,
           BSLS_COMPILERFEATURES_FORWARD_REF(VALUE_TYPE) value)
    {
        // Note that some compilers require functions declared with 'enable_if'
        // to be defined inline.

        return d_impl.insert(BSLS_COMPILERFEATURES_FORWARD(VALUE_TYPE,
                                                           value)).first;
    }

    /// Insert into this map the value of each element in the input iterator
    /// range specified by `first` through `last` (including `first`,
    /// excluding `last`).  The behavior is undefined unless `first` and
    /// `last` refer to a sequence of valid values where `first` is at a
    /// position at or before `last`.  Note that if the key of a member of
    /// the input sequence is equivalent to the key of an earlier member,
    /// the later member will not be inserted.
    template <class INPUT_ITERATOR>
    void insert(INPUT_ITERATOR first, INPUT_ITERATOR last);

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
    /// Insert into this map an element having the value of each object in
    /// the specified `values` initializer list if a value with an
    /// equivalent key is not already contained in this map.  This method
    /// requires that the (template parameter) type `KEY` be copy-insertable
    /// (see {Requirements on `KEY`, `HASH`, and `EQUAL`}).
    void insert(bsl::initializer_list<value_type> values);
#endif

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES

    /// If this map contains an entry with a key equivalent to the specified
    /// `key`, assign the specified `obj` to the `mapped_type` of that entry,
    /// and return an iterator to that entry and `false`.  Otherwise, insert a
    /// new entry into the map with the and return an iterator to that entry
    /// and `true`.  `obj` is left in a (valid) unspecified state.
    template<class M>
    bsl::pair<iterator, bool> insert_or_assign(const KEY& key, M&& obj);

    /// If this map contains an entry with a key equivalent to the specified
    /// `key`, assign the specified `obj` to the `mapped_type` of that entry,
    /// and return an iterator to that entry and `false`.  Otherwise, insert a
    /// new entry into the map with the and return an iterator to that entry
    /// and `true`.  `obj` is left in a (valid) unspecified state.
    template<class M>
    bsl::pair<iterator, bool> insert_or_assign(
                             BloombergLP::bslmf::MovableRef<KEY> key, M&& obj);

    /// If this map contains an entry with a key equivalent to the specified
    /// `key`, assign the specified `obj` to the `mapped_type` of that entry,
    /// and return an iterator to that entry and `false`.  Otherwise, insert a
    /// new entry into the map with the and return an iterator to that entry
    /// and `true`.  `obj` is left in a (valid) unspecified state.
    template <class LOOKUP_KEY, class M>
    typename bsl::enable_if<
            BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
         && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
          , bsl::pair<iterator, bool> >::type
    insert_or_assign(LOOKUP_KEY&& key, M&& obj)
    {
        iterator iter = find(key);
        if (iter != end()) {
            iter->second = std::forward<M>(obj);
            return make_pair(iter, false);                            // RETURN
        }
        return emplace(BSLS_COMPILERFEATURES_FORWARD(LOOKUP_KEY, key),
                       BSLS_COMPILERFEATURES_FORWARD(M, obj));
    }

    /// If this map contains an entry with a key equivalent to the specified
    /// `key`, assign the specified `obj` to the `mapped_type` of that entry.
    /// Otherwise, insert a new entry into the map. Return an iterator to the
    /// inserted or updated entry.  `obj` is left in a (valid) unspecified
    /// state.
    template <class MAPPED>
    iterator insert_or_assign(const_iterator, const KEY& key, MAPPED&& obj);

    /// If this map contains an entry with a key equivalent to the specified
    /// `key`, assign the specified `obj` to the `mapped_type` of that entry.
    /// Otherwise, insert a new entry into the map. Return an iterator to the
    /// inserted or updated entry.  `obj` is left in a (valid) unspecified
    /// state.
    template <class MAPPED>
    iterator insert_or_assign(const_iterator,
                              BloombergLP::bslmf::MovableRef<KEY> key,
                              MAPPED&& obj);

    /// If this map contains an entry with a key equivalent to the specified
    /// `key`, assign the specified `obj` to the `mapped_type` of that entry.
    /// Otherwise, insert a new entry into the map. Return an iterator to the
    /// inserted or updated entry.  `obj` is left in a (valid) unspecified
    /// state.
    template <class LOOKUP_KEY, class MAPPED>
    typename bsl::enable_if<
            BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
         && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
          , iterator>::type
    insert_or_assign(const_iterator, LOOKUP_KEY&& key, MAPPED&& obj)
    {
        return insert_or_assign(
                 BSLS_COMPILERFEATURES_FORWARD(LOOKUP_KEY, key),
                 BSLS_COMPILERFEATURES_FORWARD(MAPPED, obj)).first;
    }
#endif


    /// Change the capacity of this map to at least the specified
    /// `minimumCapacity`, and redistribute all the contained elements into
    /// a new sequence of entries according to their hash values.  If
    /// `0 == minimumCapacity` and `0 == size()`, the map is returned to the
    /// default constructed state.  After this call, `load_factor()` will be
    /// less than or equal to `max_load_factor()` and all iterators,
    /// pointers, and references to elements of this map are invalidated.
    void rehash(bsl::size_t minimumCapacity);

    /// Change the capacity of this map to at least a capacity that can
    /// accommodate the specified `numEntries` (accounting for the load
    /// factor invariant), and redistribute all the contained elements into
    /// a new sequence of entries according to their hash values.  If
    /// `0 == numEntries` and `0 == size()`, the map is returned to the
    /// default constructed state.  After this call, `load_factor()` will be
    /// less than or equal to `max_load_factor()` and all iterators,
    /// pointers, and references to elements of this map are invalidated.
    /// Note that this method is effectively equivalent to:
    /// ```
    ///    rehash(bsl::ceil(numEntries / max_load_factor()))
    /// ```
    void reserve(bsl::size_t numEntries);

    /// Remove all elements from this map and release all memory from this
    /// map, returning the map to the default constructed state.
    void reset();

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_PAIR_PIECEWISE_CONSTRUCTOR
    /// If a key equivalent to the specified `key` already exists in this
    /// map, return a pair containing an iterator referring to the existing
    /// item, and `false`.  Otherwise, insert into this map a newly-created
    /// `value_type` object, constructed from `key` and the specified
    /// `args`, and return a pair containing an iterator referring to the
    /// newly-created entry and `true`.  This method requires that the
    /// (template parameter) types `KEY` and `VALUE` are
    /// `emplace-constructible` from `key` and `args` respectively.  For
    /// C++03, `VALUE` must also be `copy-constructible`.
    template< class... ARGS>
    bsl::pair<iterator, bool> try_emplace(const KEY& key, ARGS&&... args);

    /// If a key equivalent to the specified `key` already exists in this
    /// map, return a pair containing an iterator referring to the existing
    /// item and `false`.  Otherwise, insert into this map a newly-created
    /// `value_type` object, constructed from `std::forward<KEY>(key)` and
    /// the specified `args`, and return a pair containing an iterator
    /// referring to the newly-created entry, and `true`.  This method
    /// requires that the (template parameter) types `KEY` and `VALUE` are
    /// `emplace-constructible` from `key` and `args` respectively.  For
    /// C++03, `VALUE` must also be `copy-constructible`.
    template <class... ARGS>
    bsl::pair<iterator, bool> try_emplace(
                                     BloombergLP::bslmf::MovableRef<KEY> key,
                                     ARGS&&...                           args);

    /// If a key equivalent to the specified `key` already exists in this map
    /// return a pair containing an iterator referring to the existing
    /// item and `false`.  Otherwise, insert into this map a newly-created
    /// `value_type` object, constructed from `std::forward<LOOKUP_KEY>(key)`
    /// and the specified `args`, and return a pair containing an iterator
    /// referring to the newly-created entry, and `true`.  This method
    /// requires that the (template parameter) types `KEY` and `VALUE` are
    /// `emplace-constructible` from `key` and `args` respectively.  For
    /// C++03, `VALUE` must also be `copy-constructible`.
    ///
    /// Note: implemented inline due to Sun CC compilation error.
    template <class LOOKUP_KEY, class... ARGS>
    typename bsl::enable_if<
            BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
         && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
          , bsl::pair<iterator, bool> >::type
    try_emplace(LOOKUP_KEY&& key, ARGS&&... args)
    {
        return d_impl.try_emplace(
              BSLS_COMPILERFEATURES_FORWARD(LOOKUP_KEY, key),
              std::piecewise_construct,
              std::forward_as_tuple(BSLS_COMPILERFEATURES_FORWARD(LOOKUP_KEY, key)),
              std::forward_as_tuple(BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...));
    }

    /// If a key equivalent to the specified `key` already exists in this
    /// map, return an iterator referring to the existing item.  Otherwise,
    /// insert into this map a newly-created `value_type` object,
    /// constructed from `key` and the specified `args`, and return an
    /// iterator referring to the newly-created entry.  This method requires
    /// that the (template parameter) types `KEY` and `VALUE` are
    /// `emplace-constructible` from `key` and `args` respectively.  For
    /// C++03, `VALUE` must also be `copy-constructible`.
    template<class... ARGS>
    iterator
    try_emplace(const_iterator, const KEY& key, ARGS&&... args);

    /// If a key equivalent to the specified `key` already exists in this
    /// map, return an iterator referring to the existing item.  Otherwise,
    /// insert into this map a newly-created `value_type` object,
    /// constructed from `std::forward<KEY>(key)` and the specified `args`,
    /// and return an iterator referring to the newly-created entry.  This
    /// method requires that the (template parameter) types `KEY` and
    /// `VALUE` are `emplace-constructible` from `key` and `args`
    /// respectively.  For C++03, `VALUE` must also be `copy-constructible`.
    template <class... ARGS>
    iterator try_emplace(const_iterator,
                         BloombergLP::bslmf::MovableRef<KEY> key,
                         ARGS&&...                           args);

    /// If a key equivalent to the specified `key` already exists in this map
    /// return an iterator referring to the existing item.  Otherwise, insert
    /// into this map a newly-created `value_type` object, constructed from
    /// `std::forward<LOOKUP_KEY>(key)` and the specified `args`, and return an
    /// iterator referring to the newly-created entry.  This method requires
    /// that the (template parameter) types `KEY` and `VALUE` are
    /// `emplace-constructible` from `key` and `args` respectively.  For C++03,
    /// `VALUE` must also be `copy-constructible`.
    ///
    /// Note: implemented inline due to Sun CC compilation error.
    template <class LOOKUP_KEY, class... ARGS>
    typename bsl::enable_if<
            BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
         && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
          , iterator>::type
    try_emplace(const_iterator, LOOKUP_KEY&& key, ARGS&&... args)
    {
        return d_impl.try_emplace(
              BSLS_COMPILERFEATURES_FORWARD(LOOKUP_KEY, key),
              std::piecewise_construct,
              std::forward_as_tuple(
                               BSLS_COMPILERFEATURES_FORWARD(LOOKUP_KEY, key)),
              std::forward_as_tuple(
                               BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...)
                  ).first;
    }

#endif   // BSLS_LIBRARYFEATURES_HAS_CPP11_PAIR_PIECEWISE_CONSTRUCTOR
#endif

                          // Iterators

    /// Return an iterator to the first element in the sequence of
    /// modifiable elements maintained by this map, or the `end` iterator if
    /// this map is empty.
    iterator begin();

    /// Return an iterator to the past-the-end element in the sequence of
    /// modifiable elements maintained by this map.
    iterator end();

                             // Aspects

    /// Exchange the value of this object as well as its hasher and equality
    /// functors with those of the specified `other` object.  The behavior
    /// is undefined unless this object was created with the same allocator
    /// as `other`.
    void swap(FlatHashMap& other);

    // ACCESSORS

    /// Return a reference providing non-modifiable access to the mapped
    /// value associated with the specified `key` in this map, if such an
    /// entry exists; otherwise throw a `std::out_of_range` exception.  Note
    /// that this method is not exception-neutral.
    const VALUE& at(const KEY& key) const;

    /// Return a reference providing non-modifiable access to the mapped
    /// value associated with a key that is equivalent to the specified `key`
    /// in this map, if such an entry exists; otherwise throw a
    /// `std::out_of_range` exception.  Note that this method is not
    /// exception-neutral.
    ///
    /// Note: implemented inline due to Sun CC compilation error.
    template <class LOOKUP_KEY>
    typename bsl::enable_if<
            BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
         && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
          , const VALUE&>::type
    at(const LOOKUP_KEY& key) const
    {
        const_iterator iter = find(key);
        if (iter == end()) {
            BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                       "FlatHashMap::at(LOOKUP_KEY) const: invalid key_value");
        }
        return iter->second;
    }

    /// Return the number of elements this map could hold if the load factor
    /// were 1.
    bsl::size_t capacity() const;

    /// Return `true` if this map contains an element having the specified
    /// `key`, and `false` otherwise.
    bool contains(const KEY& key) const;

    /// Return `true` if this map contains an element whose key is equivalent
    /// to the specified `key`.
    ///
    /// Note: implemented inline due to Sun CC compilation error.
    template <class LOOKUP_KEY>
    typename bsl::enable_if<
            BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
        &&  BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
        , bool>::type
    contains(const LOOKUP_KEY& key) const
    {
        return find(key) != end();
    }

    /// Return the number of elements in this map having the specified
    /// `key`.  Note that since a flat hash map maintains unique keys, the
    /// returned value will be either 0 or 1.
    bsl::size_t count(const KEY& key) const;

    /// Return the number of elements in this map having a key equivalent to
    /// the specified `key`.  Note that since a flat hash map maintains unique
    /// keys, the returned value will be either 0 or 1.
    ///
    /// Note: implemented inline due to Sun CC compilation error.
    template <class LOOKUP_KEY>
    typename bsl::enable_if<
            BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
         && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
          , bsl::size_t >::type
    count(const LOOKUP_KEY& key) const
    {
        return find(key) != end() ? 1 : 0;
    }

    /// Return `true` if this map contains no elements, and `false`
    /// otherwise.
    bool empty() const;

    /// Return a pair of `const_iterator`s defining the sequence of elements
    /// in this map having the specified `key`, where the first iterator is
    /// positioned at the start of the sequence and the second iterator is
    /// positioned one past the end of the sequence.  If this map contains
    /// no elements having a key equivalent to `key`, then the two returned
    /// iterators will have the same value.  Note that since a map maintains
    /// unique keys, the range will contain at most one element.
    bsl::pair<const_iterator, const_iterator> equal_range(
                                                         const KEY& key) const;

    /// Return a pair of iterators providing non-modifiable access to the
    /// sequence of `value_type` objects in this unordered map that are
    /// equivalent to the specified `key`, where the first iterator is
    /// positioned at the start of the sequence and the second iterator is
    /// positioned one past the end of the sequence.  If this unordered map
    /// contains no `value_type` objects equivalent to `key`, then the two
    /// returned iterators will have the same value.  Note that since an
    /// unordered map maintains unique keys, the range will contain at most one
    /// element.
    ///
    /// Note: implemented inline due to Sun CC compilation error.
    template <class LOOKUP_KEY>
    typename bsl::enable_if<
            BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
         && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
          , bsl::pair<const_iterator, const_iterator> >::type
    equal_range(const LOOKUP_KEY& key) const
    {
        return d_impl.equal_range(key);
    }

    /// Return a `const_iterator` referring to the element in this map
    /// having the specified `key`, or `end()` if no such entry exists in
    /// this map.
    const_iterator find(const KEY& key) const;

    /// Return a `const_iterator` referring to the element in this map
    /// having the specified `key`, or `end()` if no such entry exists in
    /// this map.
    ///
    /// Note: implemented inline due to Sun CC compilation error.
    template <class LOOKUP_KEY>
    typename bsl::enable_if<
            BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
         && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
          , const_iterator>::type
    find(const LOOKUP_KEY& key) const
    {
        return const_iterator(d_impl.find(key));
    }


    /// Return (a copy of) the unary hash functor used by this map to
    /// generate a hash value (of type `bsl::size_t`) for a `KEY` object.
    HASH hash_function() const;

    /// Return (a copy of) the binary key-equality functor that returns
    /// `true` if the value of two `KEY` objects are equivalent, and `false`
    /// otherwise.
    EQUAL key_eq() const;

    /// Return the current ratio between the number of elements in this
    /// container and its capacity.
    float load_factor() const;

    /// Return the maximum load factor allowed for this map.  Note that if
    /// an insert operation would cause the load factor to exceed
    /// `max_load_factor()`, that same insert operation will increase the
    /// capacity and rehash the entries of the container (see {Load Factor
    /// and Resizing}).  Also note that the value returned by
    /// `max_load_factor` is implementation defined and cannot be changed by
    /// the user.
    float max_load_factor() const;

    /// Return the number of elements in this map.
    bsl::size_t size() const;

                          // Iterators

    /// Return a `const_iterator` to the first element in the sequence of
    /// elements maintained by this map, or the `end` iterator if this map
    /// is empty.
    const_iterator begin() const;

    /// Return a `const_iterator` to the first element in the sequence of
    /// elements maintained by this map, or the `end` iterator if this map
    /// is empty.
    const_iterator cbegin() const;

    /// Return a `const_iterator` to the past-the-end element in the
    /// sequence of elements maintained by this map.
    const_iterator cend() const;

    /// Return a `const_iterator` to the past-the-end element in the
    /// sequence of elements maintained by this map.
    const_iterator end() const;

                           // Aspects

    /// Return the allocator used by this flat hash map to supply memory.
    bslma::Allocator *allocator() const;

    /// Format this object to the specified output `stream` at the (absolute
    /// value of) the optionally specified indentation `level`, and return a
    /// reference to the modifiable `stream`.  If `level` is specified,
    /// optionally specify `spacesPerLevel`, the number of spaces per
    /// indentation level for this and all of its nested objects.  If
    /// `level` is negative, suppress indentation of the first line.  If
    /// `spacesPerLevel` is negative, format the entire output on one line,
    /// suppressing all but the initial indentation (as governed by
    /// `level`).  If `stream` is not valid on entry, this operation has no
    /// effect.
    bsl::ostream& print(bsl::ostream& stream,
                        int           level = 0,
                        int           spacesPerLevel = 4) const;
};

// FREE OPERATORS

/// Return `true` if the specified `lhs` and `rhs` objects have the same
/// value, and `false` otherwise.  Two `FlatHashMap` objects have the same
/// value if their sizes are the same and each element contained in one is
/// equal to an element of the other.  The hash and equality functors are
/// not involved in the comparison.
template <class KEY, class VALUE, class HASH, class EQUAL>
bool operator==(const FlatHashMap<KEY, VALUE, HASH, EQUAL> &lhs,
                const FlatHashMap<KEY, VALUE, HASH, EQUAL> &rhs);

/// Return `true` if the specified `lhs` and `rhs` objects do not have the
/// same value, and `false` otherwise.  Two `FlatHashMap` objects do not
/// have the same value if their sizes are different or one contains an
/// element equal to no element of the other.  The hash and equality
/// functors are not involved in the comparison.
template <class KEY, class VALUE, class HASH, class EQUAL>
bool operator!=(const FlatHashMap<KEY, VALUE, HASH, EQUAL> &lhs,
                const FlatHashMap<KEY, VALUE, HASH, EQUAL> &rhs);

/// Write the value of the specified `map` to the specified output `stream`
/// in a single-line format, and return a reference providing modifiable
/// access to `stream`.  If `stream` is not valid on entry, this operation
/// has no effect.  Note that this human-readable format is not fully
/// specified and can change without notice.
template <class KEY, class VALUE, class HASH, class EQUAL>
bsl::ostream& operator<<(bsl::ostream&                               stream,
                         const FlatHashMap<KEY, VALUE, HASH, EQUAL>& map);

// FREE FUNCTIONS

/// Exchange the value, the hasher, and the key-equality functor of the
/// specified `a` and `b` objects.  This function provides the no-throw
/// exception-safety guarantee if the two objects were created with the same
/// allocator and the basic guarantee otherwise.
template <class KEY, class VALUE, class HASH, class EQUAL>
void swap(FlatHashMap<KEY, VALUE, HASH, EQUAL>& a,
          FlatHashMap<KEY, VALUE, HASH, EQUAL>& b);

// ============================================================================
//                  TEMPLATE AND INLINE FUNCTION DEFINITIONS
// ============================================================================

                       // ----------------------------
                       // struct FlatHashMap_EntryUtil
                       // ----------------------------

// CLASS METHODS
#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
template <class KEY, class VALUE, class ENTRY>
template <class... ARGS>
inline
void FlatHashMap_EntryUtil<KEY, VALUE, ENTRY>::construct(
                        ENTRY                                       *entry,
                        bslma::Allocator                            *allocator,
                        ARGS&&...                                    args)
{
    BSLS_ASSERT_SAFE(entry);
    bslma::ConstructionUtil::construct(
                                 entry,
                                 allocator,
                                 BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...);
}
#endif

template <class KEY, class VALUE, class ENTRY>
template <class KEY_TYPE>
inline
void FlatHashMap_EntryUtil<KEY, VALUE, ENTRY>::constructFromKey(
                        ENTRY                                       *entry,
                        bslma::Allocator                            *allocator,
                        BSLS_COMPILERFEATURES_FORWARD_REF(KEY_TYPE)  key)
{
    BSLS_ASSERT_SAFE(entry);

    bsls::ObjectBuffer<VALUE> value;

    bslma::ConstructionUtil::construct(value.address(), allocator);
    bslma::DestructorGuard<VALUE> guard(value.address());

    bslma::ConstructionUtil::construct(
                                  entry,
                                  allocator,
                                  BSLS_COMPILERFEATURES_FORWARD(KEY_TYPE, key),
                                  bslmf::MovableRefUtil::move(value.object()));
}

template <class KEY, class VALUE, class ENTRY>
inline
const KEY& FlatHashMap_EntryUtil<KEY, VALUE, ENTRY>::key(const ENTRY& entry)
{
    return entry.first;
}

                            // -----------------
                            // class FlatHashMap
                            // -----------------

// CREATORS
template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap()
: d_impl(0, HASH(), EQUAL())
{
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap(
                                              bslma::Allocator *basicAllocator)
: d_impl(0, HASH(), EQUAL(), basicAllocator)
{
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap(bsl::size_t capacity)
: d_impl(capacity, HASH(), EQUAL())
{
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap(
                                              bsl::size_t       capacity,
                                              bslma::Allocator *basicAllocator)
: d_impl(capacity, HASH(), EQUAL(), basicAllocator)
{
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap(
                                              bsl::size_t       capacity,
                                              const HASH&       hash,
                                              bslma::Allocator *basicAllocator)
: d_impl(capacity, hash, EQUAL(), basicAllocator)
{
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap(
                                              bsl::size_t       capacity,
                                              const HASH&       hash,
                                              const EQUAL&      equal,
                                              bslma::Allocator *basicAllocator)
: d_impl(capacity, hash, equal, basicAllocator)
{
}

template <class KEY, class VALUE, class HASH, class EQUAL>
template <class INPUT_ITERATOR>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap(
                                              INPUT_ITERATOR    first,
                                              INPUT_ITERATOR    last,
                                              bslma::Allocator *basicAllocator)
: d_impl(0, HASH(), EQUAL(), basicAllocator)
{
    insert(first, last);
}

template <class KEY, class VALUE, class HASH, class EQUAL>
template <class INPUT_ITERATOR>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap(
                                              INPUT_ITERATOR    first,
                                              INPUT_ITERATOR    last,
                                              bsl::size_t       capacity,
                                              bslma::Allocator *basicAllocator)
: d_impl(capacity, HASH(), EQUAL(), basicAllocator)
{
    insert(first, last);
}

template <class KEY, class VALUE, class HASH, class EQUAL>
template <class INPUT_ITERATOR>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap(
                                              INPUT_ITERATOR    first,
                                              INPUT_ITERATOR    last,
                                              bsl::size_t       capacity,
                                              const HASH&       hash,
                                              bslma::Allocator *basicAllocator)
: d_impl(capacity, hash, EQUAL(), basicAllocator)
{
    insert(first, last);
}

template <class KEY, class VALUE, class HASH, class EQUAL>
template <class INPUT_ITERATOR>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap(
                                              INPUT_ITERATOR    first,
                                              INPUT_ITERATOR    last,
                                              bsl::size_t       capacity,
                                              const HASH&       hash,
                                              const EQUAL&      equal,
                                              bslma::Allocator *basicAllocator)
: d_impl(capacity, hash, equal, basicAllocator)
{
    insert(first, last);
}

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap(
                             bsl::initializer_list<value_type>  values,
                             bslma::Allocator                  *basicAllocator)
: FlatHashMap(values.begin(),
              values.end(),
              0,
              HASH(),
              EQUAL(),
              basicAllocator)
{
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap(
                             bsl::initializer_list<value_type>  values,
                             bsl::size_t                        capacity,
                             bslma::Allocator                  *basicAllocator)
: FlatHashMap(values.begin(),
              values.end(),
              capacity,
              HASH(),
              EQUAL(),
              basicAllocator)
{
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap(
                             bsl::initializer_list<value_type>  values,
                             bsl::size_t                        capacity,
                             const HASH&                        hash,
                             bslma::Allocator                  *basicAllocator)
: FlatHashMap(values.begin(),
              values.end(),
              capacity,
              hash,
              EQUAL(),
              basicAllocator)
{
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap(
                             bsl::initializer_list<value_type>  values,
                             bsl::size_t                        capacity,
                             const HASH&                        hash,
                             const EQUAL&                       equal,
                             bslma::Allocator                  *basicAllocator)
: FlatHashMap(values.begin(),
              values.end(),
              capacity,
              hash,
              equal,
              basicAllocator)
{
}
#endif

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap(
                                            const FlatHashMap&  original,
                                            bslma::Allocator   *basicAllocator)
: d_impl(original.d_impl, basicAllocator)
{
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap(
                                       bslmf::MovableRef<FlatHashMap> original)
: d_impl(bslmf::MovableRefUtil::move(
                               bslmf::MovableRefUtil::access(original).d_impl))
{
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::FlatHashMap(
                                bslmf::MovableRef<FlatHashMap>  original,
                                bslma::Allocator               *basicAllocator)
: d_impl(bslmf::MovableRefUtil::move(
                               bslmf::MovableRefUtil::access(original).d_impl),
         basicAllocator)
{
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>::~FlatHashMap()
{
}

// MANIPULATORS
template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>&
FlatHashMap<KEY, VALUE, HASH, EQUAL>::operator=(const FlatHashMap& rhs)
{
    d_impl = rhs.d_impl;

    return *this;
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>&
FlatHashMap<KEY, VALUE, HASH, EQUAL>::operator=(
                                            bslmf::MovableRef<FlatHashMap> rhs)
{
    FlatHashMap& lvalue = rhs;

    d_impl = bslmf::MovableRefUtil::move(lvalue.d_impl);

    return *this;
}

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
template <class KEY, class VALUE, class HASH, class EQUAL>
inline
FlatHashMap<KEY, VALUE, HASH, EQUAL>&
FlatHashMap<KEY, VALUE, HASH, EQUAL>::operator=(
                                      bsl::initializer_list<value_type> values)
{
    FlatHashMap tmp(values.begin(),
                    values.end(),
                    0,
                    d_impl.hash_function(),
                    d_impl.key_eq(),
                    d_impl.allocator());

    this->swap(tmp);

    return *this;
}
#endif

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
VALUE& FlatHashMap<KEY, VALUE, HASH, EQUAL>::operator[](const KEY& key)
{
    return d_impl[key].second;
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
VALUE& FlatHashMap<KEY, VALUE, HASH, EQUAL>::operator[](bslmf::MovableRef<KEY> key)
{
    return d_impl[BSLS_COMPILERFEATURES_FORWARD(KEY, key)].second;
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
VALUE& FlatHashMap<KEY, VALUE, HASH, EQUAL>::at(const KEY& key)
{
    iterator node = d_impl.find(key);

    if (node == d_impl.end()) {
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                          "FlatHashMap<...>::at(key_type): invalid key value");
    }

    return node->second;
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
void
FlatHashMap<KEY, VALUE, HASH, EQUAL>::clear()
{
    d_impl.clear();
}

template <class KEY, class VALUE, class HASH, class EQUAL>
bsl::pair<typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator,
          typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator>
FlatHashMap<KEY, VALUE, HASH, EQUAL>::equal_range(const KEY& key)
{
    return d_impl.equal_range(key);
}

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
template <class KEY, class VALUE, class HASH, class EQUAL>
template <class... ARGS>
inline
bsl::pair<typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator, bool>
FlatHashMap<KEY, VALUE, HASH, EQUAL>::emplace(ARGS&&... args)
{
    return d_impl.emplace(BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...);
}

template <class KEY, class VALUE, class HASH, class EQUAL>
template <class... ARGS>
inline
typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator
FlatHashMap<KEY, VALUE, HASH, EQUAL>::emplace_hint(const_iterator,
                                                   ARGS&&...       args)
{
    return emplace(BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...).first;
}
#endif


template <class KEY, class VALUE, class HASH, class EQUAL>
bsl::size_t FlatHashMap<KEY, VALUE, HASH, EQUAL>::erase(const KEY& key)
{
    return d_impl.erase(key);
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator
FlatHashMap<KEY, VALUE, HASH, EQUAL>::erase(const_iterator position)
{
    BSLS_ASSERT_SAFE(position != end());

    return d_impl.erase(position);
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator
FlatHashMap<KEY, VALUE, HASH, EQUAL>::erase(iterator position)
{
    // Note that this overload is necessary to avoid ambiguity when the key is
    // an iterator.

    BSLS_ASSERT_SAFE(position != end());

    return d_impl.erase(position);
}

template <class KEY, class VALUE, class HASH, class EQUAL>
typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator
FlatHashMap<KEY, VALUE, HASH, EQUAL>::erase(const_iterator first,
                                            const_iterator last)
{
    return d_impl.erase(first, last);
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator
FlatHashMap<KEY, VALUE, HASH, EQUAL>::find(const KEY& key)
{
    return d_impl.find(key);
}

template <class KEY, class VALUE, class HASH, class EQUAL>
template <class INPUT_ITERATOR>
void FlatHashMap<KEY, VALUE, HASH, EQUAL>::insert(INPUT_ITERATOR first,
                                                  INPUT_ITERATOR last)
{
    d_impl.insert(first, last);
}

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
template <class KEY, class VALUE, class HASH, class EQUAL>
template <class MAPPED>
inline
bsl::pair<typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator, bool>
FlatHashMap<KEY, VALUE, HASH, EQUAL>::insert_or_assign(const KEY& key,
                                                       MAPPED&&   obj)
{
    iterator iter = find(key);
    if (iter != end()) {
        iter->second = std::forward<MAPPED>(obj);
        return make_pair(iter, false);                            // RETURN
    }
    return emplace(key, BSLS_COMPILERFEATURES_FORWARD(MAPPED, obj));
}

template <class KEY, class VALUE, class HASH, class EQUAL>
template <class MAPPED>
inline
bsl::pair<typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator, bool>
FlatHashMap<KEY, VALUE, HASH, EQUAL>::insert_or_assign(
                                       BloombergLP::bslmf::MovableRef<KEY> key,
                                       MAPPED&&                            obj)
{
    const KEY& lvalue = key;
    iterator iter = find(lvalue);
    if (iter != end()) {
        iter->second = std::forward<MAPPED>(obj);
        return make_pair(iter, false);                            // RETURN
    }
    return emplace(bslmf::MovableRefUtil::move(lvalue),
                   BSLS_COMPILERFEATURES_FORWARD(MAPPED, obj));
}

template <class KEY, class VALUE, class HASH, class EQUAL>
template <class MAPPED>
inline
typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator
FlatHashMap<KEY, VALUE, HASH, EQUAL>::insert_or_assign(const_iterator,
                                                       const KEY&      key,
                                                       MAPPED&&        obj)
{
    return insert_or_assign(key,
                             BSLS_COMPILERFEATURES_FORWARD(MAPPED, obj)).first;
}

template <class KEY, class VALUE, class HASH, class EQUAL>
template <class MAPPED>
inline
typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator
FlatHashMap<KEY, VALUE, HASH, EQUAL>::insert_or_assign(
                                       const_iterator,
                                       BloombergLP::bslmf::MovableRef<KEY> key,
                                       MAPPED&&                            obj)
{
    const KEY& lvalue = key;
    return insert_or_assign(bslmf::MovableRefUtil::move(lvalue),
                            BSLS_COMPILERFEATURES_FORWARD(MAPPED, obj)).first;
}
#endif

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
template <class KEY, class VALUE, class HASH, class EQUAL>
void FlatHashMap<KEY, VALUE, HASH, EQUAL>::insert(
                                      bsl::initializer_list<value_type> values)
{
    insert(values.begin(), values.end());
}
#endif

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
void FlatHashMap<KEY, VALUE, HASH, EQUAL>::rehash(bsl::size_t minimumCapacity)
{
    d_impl.rehash(minimumCapacity);
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
void FlatHashMap<KEY, VALUE, HASH, EQUAL>::reserve(bsl::size_t numEntries)
{
    d_impl.reserve(numEntries);
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
void FlatHashMap<KEY, VALUE, HASH, EQUAL>::reset()
{
    d_impl.reset();
}

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_PAIR_PIECEWISE_CONSTRUCTOR
template <class KEY, class VALUE, class HASH, class EQUAL>
template< class... ARGS>
inline
bsl::pair<typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator, bool>
FlatHashMap<KEY, VALUE, HASH, EQUAL>::try_emplace(const KEY& key,
                                                  ARGS&&...  args)
{
    return d_impl.try_emplace(
          key,
          std::piecewise_construct,
          std::forward_as_tuple(key),
          std::forward_as_tuple(BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...));
}

template <class KEY, class VALUE, class HASH, class EQUAL>
template <class... ARGS>
bsl::pair<typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator, bool>
FlatHashMap<KEY, VALUE, HASH, EQUAL>::try_emplace(
                                      BloombergLP::bslmf::MovableRef<KEY> key,
                                      ARGS&&...                           args)
{
    return d_impl.try_emplace(
          BSLS_COMPILERFEATURES_FORWARD(KEY, key),
          std::piecewise_construct,
          std::forward_as_tuple(BSLS_COMPILERFEATURES_FORWARD(KEY, key)),
          std::forward_as_tuple(BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...));
}

template <class KEY, class VALUE, class HASH, class EQUAL>
template<class... ARGS>
typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator
FlatHashMap<KEY, VALUE, HASH, EQUAL>::try_emplace(const_iterator,
                                                  const KEY&      key,
                                                  ARGS&&...       args)
{
    return d_impl.try_emplace(
          key,
          std::piecewise_construct,
          std::forward_as_tuple(key),
          std::forward_as_tuple(BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...))
          .first;
}

template <class KEY, class VALUE, class HASH, class EQUAL>
template <class... ARGS>
typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator
FlatHashMap<KEY, VALUE, HASH, EQUAL>::try_emplace(const_iterator,
                         BloombergLP::bslmf::MovableRef<KEY> key,
                         ARGS&&...                           args)
{
    return d_impl.try_emplace(
          BSLS_COMPILERFEATURES_FORWARD(KEY, key),
          std::piecewise_construct,
          std::forward_as_tuple(BSLS_COMPILERFEATURES_FORWARD(KEY, key)),
          std::forward_as_tuple(BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...))
          .first;
}
#endif   // BSLS_LIBRARYFEATURES_HAS_CPP11_PAIR_PIECEWISE_CONSTRUCTOR
#endif

                          // Iterators

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator
                                  FlatHashMap<KEY, VALUE, HASH, EQUAL>::begin()
{
    return d_impl.begin();
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::iterator
                                    FlatHashMap<KEY, VALUE, HASH, EQUAL>::end()
{
    return d_impl.end();
}

                             // Aspects

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
void FlatHashMap<KEY, VALUE, HASH, EQUAL>::swap(FlatHashMap& other)
{
    BSLS_ASSERT_SAFE(allocator() == other.allocator());

    d_impl.swap(other.d_impl);
}

// ACCESSORS
template <class KEY, class VALUE, class HASH, class EQUAL>
inline
const VALUE& FlatHashMap<KEY, VALUE, HASH, EQUAL>::at(const KEY& key) const
{
    const_iterator node = d_impl.find(key);

    if (node == d_impl.end()) {
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                    "FlatHashMap<...>::at(key_type) const: invalid key value");
    }

    return node->second;
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
bsl::size_t FlatHashMap<KEY, VALUE, HASH, EQUAL>::capacity() const
{
    return d_impl.capacity();
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
bool FlatHashMap<KEY, VALUE, HASH, EQUAL>::contains(const KEY& key) const
{
    return d_impl.contains(key);
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
bsl::size_t FlatHashMap<KEY, VALUE, HASH, EQUAL>::count(const KEY& key) const
{
    return d_impl.count(key);
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
bool FlatHashMap<KEY, VALUE, HASH, EQUAL>::empty() const
{
    return d_impl.empty();
}

template <class KEY, class VALUE, class HASH, class EQUAL>
bsl::pair<typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::const_iterator,
          typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::const_iterator>
FlatHashMap<KEY, VALUE, HASH, EQUAL>::equal_range(const KEY& key) const
{
    return d_impl.equal_range(key);
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::const_iterator
FlatHashMap<KEY, VALUE, HASH, EQUAL>::find(const KEY& key) const
{
    return d_impl.find(key);
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
HASH FlatHashMap<KEY, VALUE, HASH, EQUAL>::hash_function() const
{
    return d_impl.hash_function();
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
EQUAL FlatHashMap<KEY, VALUE, HASH, EQUAL>::key_eq() const
{
    return d_impl.key_eq();
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
float FlatHashMap<KEY, VALUE, HASH, EQUAL>::load_factor() const
{
    return d_impl.load_factor();
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
float FlatHashMap<KEY, VALUE, HASH, EQUAL>::max_load_factor() const
{
    return d_impl.max_load_factor();
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
bsl::size_t FlatHashMap<KEY, VALUE, HASH, EQUAL>::size() const
{
    return d_impl.size();
}

                          // Iterators

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::const_iterator
                      FlatHashMap<KEY, VALUE, HASH, EQUAL>::begin() const
{
    return d_impl.begin();
}
template <class KEY, class VALUE, class HASH, class EQUAL>
inline
typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::const_iterator
                     FlatHashMap<KEY, VALUE, HASH, EQUAL>::cbegin() const
{
    return d_impl.cbegin();
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::const_iterator
                       FlatHashMap<KEY, VALUE, HASH, EQUAL>::cend() const
{
    return d_impl.cend();
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
typename FlatHashMap<KEY, VALUE, HASH, EQUAL>::const_iterator
                        FlatHashMap<KEY, VALUE, HASH, EQUAL>::end() const
{
    return d_impl.end();
}

                             // Aspects

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
bslma::Allocator *FlatHashMap<KEY, VALUE, HASH, EQUAL>::allocator() const
{
    return d_impl.allocator();
}

template <class KEY, class VALUE, class HASH, class EQUAL>
bsl::ostream& FlatHashMap<KEY, VALUE, HASH, EQUAL>::print(
                                            bsl::ostream& stream,
                                            int           level,
                                            int           spacesPerLevel) const
{
    if (stream.bad()) {
        return stream;                                                // RETURN
    }

    bslim::Printer printer(&stream, level, spacesPerLevel);

    printer.start();

    const_iterator iter = begin();
    while (iter != end()) {
        printer.printValue(*iter);
        ++iter;
    }

    printer.end();

    return stream;
}

}  // close package namespace

// FREE OPERATORS
template <class KEY, class VALUE, class HASH, class EQUAL>
inline
bool bdlc::operator==(const FlatHashMap<KEY, VALUE, HASH, EQUAL>& lhs,
                      const FlatHashMap<KEY, VALUE, HASH, EQUAL>& rhs)
{
    return lhs.d_impl == rhs.d_impl;
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
bool bdlc::operator!=(const FlatHashMap<KEY, VALUE, HASH, EQUAL>& lhs,
                      const FlatHashMap<KEY, VALUE, HASH, EQUAL>& rhs)
{
    return lhs.d_impl != rhs.d_impl;
}

template <class KEY, class VALUE, class HASH, class EQUAL>
inline
bsl::ostream& bdlc::operator<<(
                            bsl::ostream&                               stream,
                            const FlatHashMap<KEY, VALUE, HASH, EQUAL>& map)
{
    return map.print(stream, 0, -1);
}

// FREE FUNCTIONS
template <class KEY, class VALUE, class HASH, class EQUAL>
inline
void bdlc::swap(FlatHashMap<KEY, VALUE, HASH, EQUAL>& a,
                FlatHashMap<KEY, VALUE, HASH, EQUAL>& b)
{
    bslalg::SwapUtil::swap(&a.d_impl, &b.d_impl);
}

// ============================================================================
//                                TYPE TRAITS
// ============================================================================

namespace bslalg {

template <class KEY, class VALUE, class HASH, class EQUAL>
struct HasStlIterators<bdlc::FlatHashMap<KEY, VALUE, HASH, EQUAL> >
: bsl::true_type {
};

}  // close namespace bslalg

namespace bslma {

template <class KEY, class VALUE, class HASH, class EQUAL>
struct UsesBslmaAllocator<bdlc::FlatHashMap<KEY, VALUE, HASH, EQUAL> >
: bsl::true_type {
};

}  // close namespace bslma
}  // close enterprise namespace

#endif // End C++11 code

#endif

// ----------------------------------------------------------------------------
// Copyright 2020 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
